# coding: utf-8

from pymel.core import *
import MaterialXS
import xml.dom.minidom
typeSetSurface = {
 'aiAmbientOcclusion',
 'aiFlat',
 'aiMixShader',
 'aiRaySwitch',
 'aiShadowMatte',
 'aiStandardHair',
 'aiStandardSurface',
 'aiSwitch',
 'aiTwoSided',
 'aiUtility',
 'aiWireframe'}


typeSetDisp = {'displacementShader'}


# Fixed(2017.12.12): export 'xgmPalette', 'xgmDescription', 'xgmSubdPath' xgen node
# Fixed(2018.01.18): export 'aiStandIn' arnold node
#TODO: 2018.03.05,
typeSetGeo = {'transform', 'mesh', 'xgmPalette', 'xgmDescription', 'xgmSubdPatch', 'aiStandIn', 'xgmSplineDescription'}


typeSetUtil = {'addDoubleLinear',
 'anisotropic',
 'blendColors',
 'blinn',
 'brownian',
 'bulge',
 'bump2d',
 'bump3d',
 'checker',
 'clearCoat',
 'cloth',
 'cloud',
 'condition',
 'contrast',
 'distanceBetween',
 'doubleShadingSwitch',
 'envChrome',
 'envCube',
 'envSphere',
 'file',
 'fluidShape',
 'fluid_utils',
 'fractal',
 'gammaCorrect',
 'global_illumination',
 'granite',
 'grid',
 'hsvToRgb',
 'layeredTexture',
 'leather',
 'lightInfo',
 'light_utils',
 'luminance',
 'marble',
 'mi_bump_flakes',
 'mia_physicalsky',
 'mib_amb_occlusion',
 'mib_glossy_reflection',
 'mib_glossy_refraction',
 'multDoubleLinear',
 'multiplyDivide',
 'noise',
 'noise_utils',
 'ocean',
 'ocean_utils',
 'particleSamplerInfo',
 'place2dTexture',
 'place3dTexture',
 'plusMinusAverage',
 'projection',
 'psdFileTex',
 'quadShadingSwitch',
 'ramp',
 #'ramp_utils',
 #'remapColor',
 #'remapHsv',
 #'remapValue',
 #'reverse',
 #'rgbToHsv',
 'rock',
 'samplerInfo',
 'setRange',
 'shading_utils',
 'singleShadingSwitch',
 'smear',
 'snow',
 'solidFractal',
 'stencil',
 'stucco',
 'studioClearCoat',
 'surfaceLuminance',
 'texture3d',
 'tripleShadingSwitch',
 'lib',
 'uvChooser',
 'vectorProduct',
 'volumeLight',
 'volumeNoise',
 'wood',
 'aiCurvature',
 'aiFlakes',
 'aiImage',
 'aiNoise',
 'aiThinFilm',
 'aiTriplanar',
 'aiWriteColor',
 'aiWriteFloat',
 'aiColorToFloat',
 'aiFloatToInt',
 'aiAbs',
 'aiAdd',
 'aiAtan',
 'aiCompare',
 'aiComplement',
 'aiCross',
 'aiDivide',
 'aiDot',
 'aiExp',
 'aiFraction',
 'aiIsFinite',
 'aiLength',
 'aiLog',
 'aiMax',
 'aiMin',
 'aiModulo',
 'aiMultiply',
 'aiNegate',
 'aiNormalize',
 'aiPow',
 'aiRandom',
 'aiReciprocal',
 'aiSign',
 'aiSqrt',
 'aiSubstract',
 'aiTrigo',
 'aiBlackbody',
 'aiBump2d',
 'aiBump3d',
 'aiClamp',
 'aiColorConvert',
 'aiColorCorrect',
 'aiColorJitter',
 'aiComplexIor',
 'aiComposite',
 'aiFacingRatio',
 'aiMotionVector',
 'aiNormalMap',
 'aiRange',
 'aiShuffle',
 'aiSpaceTransform',
 'aiUvTransform',
 'aiVectorMap',
 'aiUserDataBool',
 'aiUserDataColor',
 'aiUserDataFloat',
 'aiUserDataInt',
 'aiUserDataString',
 'aiUserDataVec2',
 'aiUserDataVector',
 'aiCache',
 'aiVolumeSampleFloat',
 'aiVolumeSampleRgb',
 'channels',
 'colorComposite',
 'colorCondition',
 'colorConstant',
 'colorCorrect',
 'colorLogic',
 'colorMask',
 'colorMath',
 'floatComposite',
 'floatCondition',
 'floatConstant',
 'floatCorrect',
 'floatLogic',
 'floatMask',
 'floatMath',
 'premultiply',
 'simplexNoise'}
arnoldTypeSetUtil = {'aiCurvature',
 'aiFlakes',
 'aiImage',
 'aiNoise',
 'aiThinFilm',
 'aiTriplanar',
 'aiWriteColor',
 'aiWriteFloat',
 'aiColorToFloat',
 'aiFloatToInt',
 'aiAbs',
 'aiAdd',
 'aiAtan',
 'aiCompare',
 'aiComplement',
 'aiCross',
 'aiDivide',
 'aiDot',
 'aiExp',
 'aiFraction',
 'aiIsFinite',
 'aiLength',
 'aiLog',
 'aiMax',
 'aiMin',
 'aiModulo',
 'aiMultiply',
 'aiNegate',
 'aiNormalize',
 'aiPow',
 'aiRandom',
 'aiReciprocal',
 'aiSign',
 'aiSqrt',
 'aiSubstract',
 'aiTrigo',
 'aiBlackbody',
 'aiBump2d',
 'aiBump3d',
 'aiClamp',
 'aiColorConvert',
 'aiColorCorrect',
 'aiColorJitter',
 'aiComplexIor',
 'aiComposite',
 'aiFacingRatio',
 'aiMotionVector',
 'aiNormalMap',
 'aiRange',
 'aiShuffle',
 'aiSpaceTransform',
 'aiUvTransform',
 'aiVectorMap',
 'aiUserDataBool',
 'aiUserDataColor',
 'aiUserDataFloat',
 'aiUserDataInt',
 'aiUserDataString',
 'aiUserDataVec2',
 'aiUserDataVector',
 'aiCache',
 'aiVolumeSampleFloat',
 'aiVolumeSampleRgb',
 'channels',
 'colorComposite',
 'colorCondition',
 'colorConstant',
 'colorCorrect',
 'colorLogic',
 'colorMask',
 'colorMath',
 'floatComposite',
 'floatCondition',
 'floatConstant',
 'floatCorrect',
 'floatLogic',
 'floatMask',
 'floatMath',
 'premultiply',
 'simplexNoise'}
colorManagementAttr = {'colorManagementEnabled',
 'colorManagementConfigFileEnabled',
 'colorManagementConfigFilePath',
 'workingSpace'}
filteredMayaAttr = {'caching',
 'nodeState',
 'instObjGroups.objectGroups.objectGroupId',
 'instObjGroups.objectGroups.objectGrpColor',
 'renderLayerInfo.renderLayerId',
 'renderLayerInfo.renderLayerRenderable',
 'renderLayerInfo.renderLayerColor',
 'explicitUvTiles.explicitUvTilePosition',
 'explicitUvTiles.explicitUvTilePositionU',
 'explicitUvTiles.explicitUvTilePositionV',
 'timewarpIn_Inmap.timewarpIn_InmapTo',
 'timewarpIn_Inmap.timewarpIn_InmapFrom',
 'timewarpIn_Outmap.timewarpIn_OutmapTo',
 'timewarpIn_Outmap.timewarpIn_OutmapFrom',
 'objectColor',


 # Fixed: 2017.11.09 过滤掉 file 节点上面的 filter, filterOffset参数
 'filter',
 'filterOffset',
}
rampUtilNodes = {'ramp',
 'remapValue',
 'remapHsv',
 'remapColor',
 'ocean',
 'oceanShader',
 'rampShader',
 'layeredShader'}
filteredRampUtils = {'colorEntryList.color',
 'colorEntryList.colorR',
 'colorEntryList.colorG',
 'colorEntryList.colorB',
 'colorEntryList.position',
 'red.red_FloatValue',
 'red.red_Position',
 'red.red_Interp',
 'green.green_FloatValue',
 'green.green_Position',
 'green.green_Interp',
 'blue.blue_FloatValue',
 'blue.blue_Position',
 'blue.blue_Interp',
 'value.value_FloatValue',
 'value.value_Position',
 'value.value_Interp',
 'hue.hue_FloatValue',
 'hue.hue_Position',
 'hue.hue_Interp',
 'saturation.saturation_FloatValue',
 'saturation.saturation_Position',
 'saturation.saturation_Interp',
 'color.color_Color',
 'color.color_Position',
 'color.color_Interp',
 'color.color_ColorR',
 'color.color_ColorG',
 'color.color_ColorB',
 'red',
 'green',
 'blue',
 'hue',
 'saturation',
 'value',
 'waveHeight',
 'waveTurbulence',
 'wavePeaking',
 'waveHeight.waveHeight_Position',
 'waveHeight.waveHeight_FloatValue',
 'waveHeight.waveHeight_Interp',
 'waveTurbulence.waveTurbulence_Position',
 'waveTurbulence.waveTurbulence_FloatValue',
 'waveTurbulence.waveTurbulence_Interp',
 'wavePeaking.wavePeaking_Position',
 'wavePeaking.wavePeaking_FloatValue',
 'wavePeaking.wavePeaking_Interp',
 'environment',
 'environment.environment_Position',
 'environment.environment_Color',
 'environment.environment_ColorR',
 'environment.environment_ColorG',
 'environment.environment_ColorB',
 'environment.environment_Interp',
 'transparency.transparency_Position',
 'transparency.transparency_Color',
 'transparency.transparency_ColorR',
 'transparency.transparency_ColorG',
 'transparency.transparency_ColorB',
 'transparency',
 'transparency.transparency_Interp',
 'incandescence.incandescence_Position',
 'incandescence.incandescence_Color',
 'incandescence.incandescence_ColorR',
 'incandescence.incandescence_ColorG',
 'incandescence.incandescence_ColorB',
 'incandescence',
 'incandescence.incandescence_Interp',
 'specularColor.specularColor_Position',
 'specularColor.specularColor_Color',
 'specularColor.specularColor_ColorR',
 'specularColor.specularColor_ColorG',
 'specularColor.specularColor_ColorB',
 'specularColor',
 'specularColor.specularColor_Interp',
 'reflectivity.reflectivity_Position',
 'reflectivity.reflectivity_FloatValue',
 'reflectivity',
 'reflectivity.reflectivity_Interp',
 'specularRollOff.specularRollOff_Position',
 'specularRollOff.specularRollOff_FloatValue',
 'specularRollOff.specularRollOff_Interp',
 'specularRollOff',
 'inputs',
 'inputs.transparency',
 'inputs.transparencyR',
 'inputs.transparencyG',
 'inputs.transparencyB',
 'inputs.color',
 'inputs.colorR',
 'inputs.colorG',
 'inputs.colorB',
 'inputs.glowColor',
 'inputs.glowColorR',
 'inputs.glowColorG',
 'inputs.glowColorB'}

#Fixed, filter lambert,phone,blinn
filteredMayaDefaults = {'particleCloud1', 'initialParticleSE', 'lambert1'}
xmlSavePath = ''

hasMultMat = {}

def __CreateMaterial(materialName, shaderName):
    sg = MaterialXS.Material(materialName)
    sg.children[shaderName] = MaterialXS.ShaderRef(shaderName, 'surface')
    return sg


def __TestTupleDefaultValue(nodeAttr, modAttr):
    notEqual = False
    for i, a in enumerate(nodeAttr.getAttr(modAttr)):
        if round(nodeAttr.getAttr(modAttr)[i], 3) != round(attributeQuery(modAttr, node=nodeAttr, listDefault=True)[i], 3):
            notEqual = True

    return notEqual


def __ValidateArrayValues(inTuple, typeOf):
    outTuple = ''
    if typeOf == 'tuple':
        for x in range(len(inTuple)):
            validValue = str(round(inTuple[x], 3))
            if outTuple == '':
                outTuple = validValue
            else:
                outTuple = outTuple + ',' + validValue

    if typeOf == 'array':
        for x in range(len(inTuple)):
            validValue = str(inTuple[x])
            if outTuple == '':
                outTuple = validValue
            else:
                outTuple = outTuple + ',' + validValue

    elif typeOf == 'multiArray2D':
        for x in range(len(inTuple)):
            validValue = str(round(inTuple[x], 3))
            if outTuple == '':
                outTuple = validValue
            elif x % 2 == 0:
                outTuple = outTuple + ' ' + validValue
            else:
                outTuple = outTuple + ',' + validValue

    elif typeOf == 'multiArray3D':
        for x in range(len(inTuple)):
            validValue = str(round(inTuple[x], 3))
            if outTuple == '':
                outTuple = validValue
            elif x % 3 == 0:
                outTuple = outTuple + ' ' + validValue
            else:
                outTuple = outTuple + ',' + validValue

    return outTuple


def __GetRampValuesFromAttr(rampAttr, rampNode, targetShadingNode, typeOfRamp):
    if typeOfRamp == 'color':
        i_colors = []
        i_colorPositions = []
        for i in range(len(rampNode.getAttr(rampAttr, multiIndices=1))):
            i_colors.extend(rampNode.getAttr(rampAttr + '[' + str(i) + ']' + '.color'))
            i_colorPositions.append(rampNode.getAttr(rampAttr + '[' + str(i) + ']' + '.position'))

        targetShadingNode.children['i_colors'] = MaterialXS.Parameter('i_colors', 'Color3ArrayAttribute', __ValidateArrayValues(i_colors, 'multiArray3D'))
        targetShadingNode.children['i_colorPositions'] = MaterialXS.Parameter('i_colorPositions', 'FloatArrayAttribute', __ValidateArrayValues(i_colorPositions, 'tuple'))
    elif typeOfRamp == 'float':
        i_value = []
        i_valuePos = []
        i_valueInterp = []
        for i in range(len(rampNode.getAttr(rampAttr, multiIndices=1))):
            i_value.append(rampNode.getAttr(rampAttr + '[' + str(i) + '].' + rampAttr + '_FloatValue'))
            i_valuePos.append(rampNode.getAttr(rampAttr + '[' + str(i) + '].' + rampAttr + '_Position'))
            i_valueInterp.append(rampNode.getAttr(rampAttr + '[' + str(i) + '].' + rampAttr + '_Interp'))

        targetShadingNode.children['i_' + rampAttr + '_FloatValue'] = MaterialXS.Parameter('i_' + rampAttr + '_FloatValue', 'FloatArrayAttribute', __ValidateArrayValues(i_value, 'tuple'))
        targetShadingNode.children['i_' + rampAttr + '_Position'] = MaterialXS.Parameter('i_' + rampAttr + '_Position', 'FloatArrayAttribute', __ValidateArrayValues(i_valuePos, 'tuple'))
        targetShadingNode.children['i_' + rampAttr + '_Interp'] = MaterialXS.Parameter('i_' + rampAttr + '_Interp', 'IntArrayAttribute', __ValidateArrayValues(i_valueInterp, 'array'))
    elif typeOfRamp == 'colorValue':
        i_colors = []
        i_colorPositions = []
        i_colorInterp = []
        for i in range(len(rampNode.getAttr(rampAttr, multiIndices=1))):
            i_colors.extend(rampNode.getAttr(rampAttr + '[' + str(i) + '].' + rampAttr + '_Color'))
            i_colorPositions.append(rampNode.getAttr(rampAttr + '[' + str(i) + '].' + rampAttr + '_Position'))
            i_colorInterp.append(rampNode.getAttr(rampAttr + '[' + str(i) + '].' + rampAttr + '_Interp'))

        targetShadingNode.children['i_' + rampAttr + '_Color'] = MaterialXS.Parameter('i_' + rampAttr + '_Color', 'Color3ArrayAttribute', __ValidateArrayValues(i_colors, 'multiArray3D'))
        targetShadingNode.children['i_' + rampAttr + '_Position'] = MaterialXS.Parameter('i_' + rampAttr + '_Position', 'FloatArrayAttribute', __ValidateArrayValues(i_colorPositions, 'tuple'))
        targetShadingNode.children['i_' + rampAttr + 'Interp'] = MaterialXS.Parameter('i_' + rampAttr + '_Interp', 'IntArrayAttribute', __ValidateArrayValues(i_colorInterp, 'array'))
    elif typeOfRamp == 'layered':
        i_colors = []
        i_colorPositions = []
        i_colorInterp = []
        for i in range(len(rampNode.getAttr(rampAttr, multiIndices=1))):
            i_colors.extend(rampNode.getAttr(rampAttr + '[' + str(i) + '].' + rampAttr + '_Color'))
            i_colorPositions.append(rampNode.getAttr(rampAttr + '[' + str(i) + '].' + rampAttr + '_Position'))
            i_colorInterp.append(rampNode.getAttr(rampAttr + '[' + str(i) + '].' + rampAttr + '_Interp'))

        targetShadingNode.children['i_' + rampAttr + '_Color'] = MaterialXS.Parameter('i_' + rampAttr + '_Color', 'Color3ArrayAttribute', __ValidateArrayValues(i_colors, 'multiArray3D'))
        targetShadingNode.children['i_' + rampAttr + '_Position'] = MaterialXS.Parameter('i_' + rampAttr + '_Position', 'FloatArrayAttribute', __ValidateArrayValues(i_colorPositions, 'tuple'))
        targetShadingNode.children['i_' + rampAttr + 'Interp'] = MaterialXS.Parameter('i_' + rampAttr + '_Interp', 'IntArrayAttribute', i_colorInterp)


def __CompareDefaultValue(modAttr, nodeAttr, targetShadingNode):
    notEqual = False

    if isinstance(nodeAttr.getAttr(modAttr), bool):
        if nodeAttr.getAttr(modAttr) != attributeQuery(modAttr, node=nodeAttr, listDefault=True)[0]:
            notEqual = True

            targetShadingNode.children['i_' + modAttr] = MaterialXS.Parameter('i_' + modAttr, MaterialXS.kBooleanTag, nodeAttr.getAttr(modAttr))
    elif isinstance(nodeAttr.getAttr(modAttr), tuple):
        if __TestTupleDefaultValue(nodeAttr, modAttr):
            if len(nodeAttr.getAttr(modAttr)) > 2:
                targetShadingNode.children['i_' + modAttr] = MaterialXS.Parameter('i_' + modAttr, MaterialXS.kColor3Tag, __ValidateArrayValues(nodeAttr.getAttr(modAttr), 'tuple'))
            else:
                targetShadingNode.children['i_' + modAttr] = MaterialXS.Parameter('i_' + modAttr, MaterialXS.kVector2Tag, __ValidateArrayValues(nodeAttr.getAttr(modAttr), 'tuple'))

        # Fixed: 2018.01.31, 修复 mtoa 中 blendColors 与 ktoa 中 mix_rgba 默认值不同的问题，例如：mtoa中color1,color2的type默认为“红蓝”，ktoa中默认为“黑”
        if objectType(nodeAttr) == 'blendColors':
            targetShadingNode.children['i_color1'] = MaterialXS.Parameter('i_color1',
                                                                          MaterialXS.kColor3Tag,
                                                                          __ValidateArrayValues(
                                                                              nodeAttr.getAttr('color1'), 'tuple'))
            targetShadingNode.children['i_color2'] = MaterialXS.Parameter('i_color2',
                                                                          MaterialXS.kColor3Tag,
                                                                          __ValidateArrayValues(
                                                                              nodeAttr.getAttr('color2'), 'tuple'))
    elif isinstance(nodeAttr.getAttr(modAttr), float):
        # if modAttr[-1:] == 'R' and modAttr[-3:] == 'IOR' or modAttr[-1:] == 'G' or modAttr[-1:] == 'B':

        # Fixed: 2018.1.5 allow "specularIOR" passed
        if modAttr[-1:] == 'R' and modAttr[-3:] != 'IOR' or modAttr[-1:] == 'G' or modAttr[-1:] == 'B':
            # print '-------------------------'
            # print modAttr
            if attributeQuery(modAttr[:-1], node=nodeAttr, exists=True) and len(listConnections(nodeAttr + '.' + modAttr[:-1])) > 0:
                return
            if attributeQuery(modAttr[:-1], node=nodeAttr, exists=True) and __TestTupleDefaultValue(nodeAttr, modAttr[:-1]):
                return
        elif round(nodeAttr.getAttr(modAttr), 3) != round(attributeQuery(modAttr, node=nodeAttr, listDefault=True)[0], 3):
            notEqual = True

            targetShadingNode.children['i_' + modAttr] = MaterialXS.Parameter('i_' + modAttr, MaterialXS.kFloatTag, nodeAttr.getAttr(modAttr), 3)
            # print '---node----%s' % nodeAttr

    elif isinstance(nodeAttr.getAttr(modAttr), int):
        if modAttr != 'octaves':
            # print '-------------------'
            # print nodeAttr
            if nodeAttr.getAttr(modAttr) != attributeQuery(modAttr, node=nodeAttr, listDefault=True)[0]:
                notEqual = True
                if attributeQuery(modAttr, node=nodeAttr, enum=True):
                    if nodeAttr.nodeType() in arnoldTypeSetUtil:
                        targetShadingNode.children['i_' + modAttr] = MaterialXS.Parameter('i_' + modAttr, MaterialXS.kStringTag, nodeAttr.getAttr(modAttr, asString=True))
                    else:
                        targetShadingNode.children['i_' + modAttr] = MaterialXS.Parameter('i_' + modAttr, MaterialXS.kIntegerTag, nodeAttr.getAttr(modAttr))

            #Fixed: 2018.01.31, 修复 mtoa 中 ramp 与 ktoa 中 ramp_rgb 默认值不同的问题，例如：mtoa中ramp的type默认为“v”，ktoa中默认为“custom”
            elif objectType(nodeAttr) == 'ramp':
                # print '-------------------'
                # print nodeAttr
                targetShadingNode.children['i_type'] = MaterialXS.Parameter('i_type',
                                                                                  MaterialXS.kIntegerTag,
                                                                                  nodeAttr.getAttr('type'))



        elif nodeAttr.getAttr(modAttr) != int(attributeQuery(modAttr, node=nodeAttr, listDefault=True)[0]):
            targetShadingNode.children['i_' + modAttr] = MaterialXS.Parameter('i_' + modAttr, MaterialXS.kIntegerTag, nodeAttr.getAttr(modAttr))


def __GetModifiedValues(nodeAttr, mtlAttr, targetShadingNode):
    if nodeAttr.nodeType() == 'file' or nodeAttr.nodeType() == 'psdFileTex':
        targetShadingNode.children['i_filename'] = MaterialXS.Parameter('i_filename', MaterialXS.kFilenameTag, nodeAttr.getAttr('fileTextureName'))
    if nodeAttr.nodeType() == 'aiImage':
        targetShadingNode.children['i_filename'] = MaterialXS.Parameter('i_filename', MaterialXS.kFilenameTag, nodeAttr.getAttr('filename'))
    if attributeQuery('colorSpace', node=nodeAttr, exists=True):
        targetShadingNode.children['i_colorSpace'] = MaterialXS.Parameter('i_colorSpace', MaterialXS.kStringTag, nodeAttr.getAttr('colorSpace'))
    if nodeAttr.nodeType() != 'place3dTexture':
        for modAttr in mtlAttr:
            if modAttr not in filteredMayaAttr and nodeAttr.nodeType() not in rampUtilNodes and modAttr not in colorManagementAttr:
                __CompareDefaultValue(modAttr, nodeAttr, targetShadingNode)
            elif modAttr not in filteredMayaAttr and modAttr not in filteredRampUtils and nodeAttr.nodeType() in rampUtilNodes:
                __CompareDefaultValue(modAttr, nodeAttr, targetShadingNode)

        if nodeAttr.nodeType() == 'ramp':
            __GetRampValuesFromAttr('colorEntryList', nodeAttr, targetShadingNode, 'color')
        elif nodeAttr.nodeType() == 'remapColor':
            __GetRampValuesFromAttr('red', nodeAttr, targetShadingNode, 'float')
            __GetRampValuesFromAttr('green', nodeAttr, targetShadingNode, 'float')
            __GetRampValuesFromAttr('blue', nodeAttr, targetShadingNode, 'float')
        elif nodeAttr.nodeType() == 'remapValue':
            __GetRampValuesFromAttr('value', nodeAttr, targetShadingNode, 'float')
            __GetRampValuesFromAttr('color', nodeAttr, targetShadingNode, 'colorValue')
        elif nodeAttr.nodeType() == 'remapHsv':
            __GetRampValuesFromAttr('hue', nodeAttr, targetShadingNode, 'float')
            __GetRampValuesFromAttr('saturation', nodeAttr, targetShadingNode, 'float')
            __GetRampValuesFromAttr('value', nodeAttr, targetShadingNode, 'float')
        elif nodeAttr.nodeType() == 'ocean':
            __GetRampValuesFromAttr('waveHeight', nodeAttr, targetShadingNode, 'float')
            __GetRampValuesFromAttr('waveTurbulence', nodeAttr, targetShadingNode, 'float')
            __GetRampValuesFromAttr('wavePeaking', nodeAttr, targetShadingNode, 'float')
        elif nodeAttr.nodeType() == 'oceanShader':
            __GetRampValuesFromAttr('waveHeight', nodeAttr, targetShadingNode, 'float')
            __GetRampValuesFromAttr('waveTurbulence', nodeAttr, targetShadingNode, 'float')
            __GetRampValuesFromAttr('wavePeaking', nodeAttr, targetShadingNode, 'float')
            __GetRampValuesFromAttr('environment', nodeAttr, targetShadingNode, 'colorValue')
        elif nodeAttr.nodeType() == 'rampShader':
            __GetRampValuesFromAttr('color', nodeAttr, targetShadingNode, 'colorValue')
            __GetRampValuesFromAttr('transparency', nodeAttr, targetShadingNode, 'colorValue')
            __GetRampValuesFromAttr('incandescence', nodeAttr, targetShadingNode, 'colorValue')
            __GetRampValuesFromAttr('specularColor', nodeAttr, targetShadingNode, 'colorValue')
            __GetRampValuesFromAttr('specularRollOff', nodeAttr, targetShadingNode, 'float')
            __GetRampValuesFromAttr('reflectivity', nodeAttr, targetShadingNode, 'float')
            __GetRampValuesFromAttr('environment', nodeAttr, targetShadingNode, 'colorValue')
    else:
        TRS = ['translate',
         'rotate',
         'scale',
         'rotateAxis']
        AXS = ['X', 'Y', 'Z']
        for i in range(len(TRS)):
            for j in range(len(AXS)):
                __CompareDefaultValue(TRS[i] + AXS[j], nodeAttr, targetShadingNode)

        __CompareDefaultValue('shearXY', nodeAttr, targetShadingNode)
        __CompareDefaultValue('shearXZ', nodeAttr, targetShadingNode)
        __CompareDefaultValue('shearYZ', nodeAttr, targetShadingNode)


def __GetConnectionsOnNode(nodeShdr, shaderType):
    mtlXShadingNode = MaterialXS.Shader(nodeShdr, shaderType, nodeShdr.nodeType())
    nodeAttr = listAttr(nodeShdr, visible=True, output=True, write=True, connectable=True)
    __GetModifiedValues(nodeShdr, nodeAttr, mtlXShadingNode)
    for con in listConnections(nodeShdr, connections=True, destination=False, plugs=True):
        inputPlug = con[0].split('.', 1)[1]
        sourceNode = con[1].split('.', 1)[0]
        sourcePlug = con[1].split('.', 1)[1]
        sourceNodeType = ls(sourceNode)[0].nodeType()
        if sourceNodeType in typeSetUtil or sourceNodeType in typeSetDisp or sourceNodeType in typeSetSurface:
            mtlXShadingNode.children['i_' + inputPlug] = MaterialXS.CoShader('i_' + inputPlug, sourceNode, 'o_' + sourcePlug)
        else:
            print 'Discarding connection on [' + con[0].split('.', 1)[0] + '.' + inputPlug + '] ' + 'coming from [' + sourceNode + '] ' + 'Not supported node'

    return mtlXShadingNode


def __GetGeometryPath(meshAssignList, sgName):
    strGeoPath = ' '
    validMesh = []
    for mesh in meshAssignList:
        if mesh.nodeType() in typeSetGeo:
            validMesh.append(mesh.fullPathName().replace('|', '/'))

    if len(validMesh) > 0:
        for valid in validMesh:

            #Fixed: valid multi materials
            sgn = ''
            # print hasMultMat.keys()
            # print '---------------%s' %valid
            if hasMultMat.has_key(valid):
                if hasMultMat[valid]:
                    sgn = '/%s' %sgName

            # TODO(2018.02.28): Remove all leading path before '_geometry' path
            if strGeoPath == ' ':
                strGeoPath = remove_leading_path(valid) + sgn
            else:
                strGeoPath = strGeoPath + ', ' + remove_leading_path(valid) + sgn

    #Fixed: 2018.02.07 Remove the First level "*_normal_model_GRP"
    # print '----------------------------------'
    # print strGeoPath

    return strGeoPath


def remove_leading_path(path):

    ps = path.split('/')

    pos = 0
    for i in range(len(ps)):

        if ps[i].find('_geometry') != -1:

            pos = i

            break

    return '/' + '/'.join(ps[i:])




def __ExportSGtoMtlX(sgName, mtlXObj):
    mayaMtl = listConnections(sgName + '.surfaceShader')[0]
    meshAssign = listConnections(sgName + '.dagSetMembers')
    meshCollection = MaterialXS.Collection(sgName + 'Collection')
    nameAdd = sgName + '_KatCollection'


    meshCollection.children[nameAdd] = MaterialXS.CollectionAdd(nameAdd, __GetGeometryPath(meshAssign,sgName))
    mtlXSG = __CreateMaterial(sgName, mayaMtl)
    mtlXObj.children[sgName] = mtlXSG
    if attributeQuery('._3delight_edgecolor', node=sgName, exists=True):
        if len(listConnections(sgName + '._3delight_edgecolor')):
            currentShadingType = mtlXSG.children[mayaMtl].getShadingType()
            outlineColor = listConnections(sgName + '._3delight_edgecolor')[0]
            mtlXSG.children[mayaMtl].setShadingType(currentShadingType + ',outlineColor')
        if len(listConnections(sgName + '._3delight_edgewidthscale')):
            currentShadingType = mtlXSG.children[mayaMtl].getShadingType()
            outlineWidth = listConnections(sgName + '._3delight_edgewidthscale')[0]
            mtlXSG.children[mayaMtl].setShadingType(currentShadingType + ',outlineScale')
        if len(listConnections(sgName + '._3delight_edgethresholdscale')):
            currentShadingType = mtlXSG.children[mayaMtl].getShadingType()
            outlineWidth = listConnections(sgName + '._3delight_edgethresholdscale')[0]
            mtlXSG.children[mayaMtl].setShadingType(currentShadingType + ',outlineTreshold')
    mtlXObj.children[mayaMtl] = __GetConnectionsOnNode(mayaMtl, 'surface')
    if len(listConnections(sgName + '.displacementShader')) > 0:
        mayaDisp = listConnections(sgName + '.displacementShader')[0]
        mtlXSG.children['displacement'] = MaterialXS.ShaderRef(mayaDisp, 'displacement')
        mtlXObj.children[mayaDisp] = __GetConnectionsOnNode(mayaDisp, 'displacement')
    if len(meshAssign) > 0:
        mtlXSG.children[sgName + 'Col'] = meshCollection


def __ExportMaterialToMtlX(mat, mtlX):
    if mat == 'lambert1':
        sg = listConnections(mat, d=True, type='shadingEngine')[1]
    else:
        sg = listConnections(mat, d=True, type='shadingEngine')[0]


    __ExportSGtoMtlX(sg, mtlX)
    involvedNodes = []
    currentConnections = listConnections(mat, destination=False, source=True)

    if len(listConnections(sg + '.displacementShader')) > 0:
        involvedNodes.append(listConnections(sg + '.displacementShader')[0])
    if len(currentConnections) > 0:
        for con in currentConnections:
            #if con.nodeType() in typeSetUtil:

            # Fixed: 为了兼容aiMixShader，因此允许surface shader 通过
            if con.nodeType() in typeSetUtil or con.nodeType() in typeSetSurface:
                if con not in involvedNodes:
                    involvedNodes.append(con)

    if len(involvedNodes) > 0:
        __TraverseNodeArray(involvedNodes)
        for util in involvedNodes:
            mtlX.children[util] = __GetConnectionsOnNode(util, 'utility')


def __ExportAllShadingNetworks(includeNotAssigned):

    supportedSG = []
    mtlX = MaterialXS.MaterialX()
    if includeNotAssigned:
        supportedSG = [ x for x in ls(exactType='shadingEngine') if len(listConnections(x + '.surfaceShader')) > 0 and x.name() not in filteredMayaDefaults ]
    else:
        supportedSG = [ x for x in ls(exactType='shadingEngine') if len(listConnections(x + '.surfaceShader')) > 0 and x.name() not in filteredMayaDefaults and len(listConnections(x + '.dagSetMembers')) > 0 ]
    for validSG in supportedSG:
        mat = listConnections(validSG + '.surfaceShader')[0]
        if mat.nodeType() in typeSetSurface:
            __ExportMaterialToMtlX(mat, mtlX)
        else:
            print 'Discarded ' + mat.name() + ': Not supported Material'

    data = str(mtlX)
    return data


def __TraverseNodeArray(involvedNodes):
    for node in involvedNodes:
        if len(listConnections(node, destination=False, source=True)) > 0:
            nodeConnections = listConnections(node, destination=False, source=True)
            for con in nodeConnections:
                if con.nodeType() in typeSetUtil or con.nodeType() in typeSetSurface or con.nodeType() in typeSetDisp:
                    if con not in involvedNodes:
                        involvedNodes.append(con)


def __ExportSelectedMaterials(selectedMat):
    mtlX = MaterialXS.MaterialX()
    for mat in selectedMat:
        __ExportMaterialToMtlX(mat, mtlX)

    data = str(mtlX)
    return data


def __SaveXMLFile(data):
    global xmlSavePath
    f = ''
    if xmlSavePath[-3:] == 'xml':
        f = open(xmlSavePath, 'w')
    else:
        f = open(xmlSavePath + '.xml', 'w')
    f.write(data)
    f.close()


def __SetXMLFilePath():
    global xmlSavePath
    savePath = fileDialog2(fm=0, caption='J CUBE Multiverse - MaterialX Write', optionsUIInit='mvMaterialXWriteUIInit', optionsUICreate='mvMaterialXUICreate', ff='MaterialX (.xml)(*.xml);;All Files (*.*)', dialogStyle=2)
    if savePath != None:
        xmlSavePath = savePath[0]

    return savePath


def __ValidateSceneMats():
    matInScene = [ x for x in ls(materials=True) if x.nodeType() in typeSetSurface and x.name() not in filteredMayaDefaults ]
    if len(matInScene) > 0:
        return True
    else:
        return False


def __ValidateMeshAssignment(shape, currMatSel):
    # shapeSG = listConnections(shape, d=True, type='shadingEngine')[0]
    # if shapeSG not in filteredMayaDefaults:
    #     if len(listConnections(shapeSG + '.surfaceShader')) == 0:
    #         warning('DISCARDED ' + shapeSG + ': has no surface shader attached!')
    #     elif listConnections(shapeSG + '.surfaceShader')[0].nodeType() in typeSetSurface:
    #         if listConnections(shapeSG + '.surfaceShader')[0] not in currMatSel:
    #             currMatSel.append(listConnections(shapeSG + '.surfaceShader')[0])
    #Fixed:
    tmp = listConnections(shape, d=True, type='shadingEngine')

    shapeSGs = list(set(tmp))
    if len(shapeSGs)>1:
        hasMultMat[shape.fullPathName().replace('|', '/')] = True
    elif len(shapeSGs)==1:
        hasMultMat[shape.fullPathName().replace('|', '/')] = False

    for shapeSG in shapeSGs:
        if shapeSG not in filteredMayaDefaults:
            if len(listConnections(shapeSG + '.surfaceShader')) == 0:
                warning('DISCARDED ' + shapeSG + ': has no surface shader attached!')
            elif listConnections(shapeSG + '.surfaceShader')[0].nodeType() in typeSetSurface:
                if listConnections(shapeSG + '.surfaceShader')[0] not in currMatSel:
                    currMatSel.append(listConnections(shapeSG + '.surfaceShader')[0])


def __SendWarning():
    warning('Warning: No valid selection was done.')
    confirmDialog(title='J CUBE Multiverse', message='Warning: invalid selection.\n\nPlease select transform nodes containing shapes to which supported materials are assigned\nor directly select materials from the Hypershade/NodeGraph.\nSupported material shading networks: native Maya, 3Delight and Arnold.', button=['OK'], defaultButton='Ok', dismissString='No')


def mvMaterialXWrite():
    if len(ls(sl=True)) == 0 and __ValidateSceneMats():
        if confirmDialog(title='J CUBE Multiverse', message='Warning: No selection.\n\nContinuing will export all materials. Continue?', button=['Yes', 'No'], defaultButton='Yes', cancelButton='No', dismissString='No') == 'Yes':
            if confirmDialog(title='J CUBE Multiverse', message='All materials assigned to geometry will be exported.\n\nInclude unassigned materials?', button=['Yes', 'No'], defaultButton='Yes', cancelButton='No', dismissString='No') == 'Yes':
                if __SetXMLFilePath() != None:
                    __SaveXMLFile(__ExportAllShadingNetworks(True))
                else:
                    warning('MaterialX Export Cancelled')
            elif __SetXMLFilePath() != None:
                __SaveXMLFile(__ExportAllShadingNetworks(False))
            else:
                warning('MaterialX Export Cancelled')
    elif len(ls(sl=True)) > 0:
        currSelection = [ x for x in ls(sl=True) if x.nodeType() in typeSetSurface or x.nodeType() in typeSetGeo ]
        # currSelection = [listRelatives(shape, shape=True)[0] for shape in currSelection]
        currMatSel = [ x for x in currSelection if x.nodeType() in typeSetSurface and x.name() not in filteredMayaDefaults ]
        currGeoSel = [ x for x in currSelection if x.nodeType() in typeSetGeo ]


        for geo in currGeoSel:
            if geo.nodeType() == 'mesh' or geo.nodeType() == 'xgmSubdPatch':
                __ValidateMeshAssignment(geo, currMatSel)
            else:
                # shs = listRelatives(geo, allDescendents=True, shapes=True)
                # Fixed: Filter the intermediate shape
                try:
                    shs = listRelatives(geo, allDescendents=True, noIntermediate=True, shapes=True)
                except:
                    shs = listRelatives(geo, allDescendents=True, shapes=True)

                if len(shs) > 0:
                    for sh in shs:

                        # Fixed(2017.12.12): export 'xgmPalette', 'xgmDescription', 'xgmSubdPath' xgen node
                        if sh.nodeType() == 'mesh' or \
                                        sh.nodeType() == 'xgmPalette' or \
                                        sh.nodeType() == 'xgmDescription' or \
                                        sh.nodeType() == 'xgmSubdPatch' or \
                                        sh.nodeType() == 'xgmSplineDescription' or \
                                        sh.nodeType() == 'aiStandIn':
                            # print currMatSel
                            __ValidateMeshAssignment(sh, currMatSel)
                        else:
                            warning(sh.name() + ' will be skipped from current selection')

        if len(currMatSel) > 0:
            if __SetXMLFilePath() != None:
                __SaveXMLFile(__ExportSelectedMaterials(currMatSel))
            else:
                warning('MaterialX Export Cancelled')
        else:
            __SendWarning()
    else:

        __SendWarning()
